/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package beantown;

import econosim.*;
import java.util.*;
import simframe.simulation.*;
import simframe.util.*;

/**
 *
 * @author Steve Noble
 */
public class Producer extends ProfitAgent {

    // Actions that Producers perform
    public static final Swarm.SwarmAction<Producer> createOffers = new Swarm.SwarmAction<Producer>() {
        @Override
        public void exec(Producer firm) {
            firm.createOffers();
        }
    };

    public static final Swarm.SwarmAction<Producer> processDividends = new Swarm.SwarmAction<Producer>() {
        @Override
        public void exec(Producer firm) {
            firm.processDividends();
        }
    };


  Set<TransActionAgent> owners;

 private final Market market;
 private final Location loc;

  // margin is a bad word maybe- but this determines how much of net goes into
  // reported profit and how much goes into internal saving
  double margin;     // what my margin currently is
  // dims are the size of the world
  Producer(Market market, Location loc)
  {
	 this.loc = loc;
     this.market = market;
	  
     owners = new HashSet<TransActionAgent>();

     margin = 0.5;
     
     reset();
  }

  // update my parameters
  public void updateMargin( double val)
  {
    margin = val;
  }

  // reset the simulation
   public void reset()
  {
     setSavings(1000.0);
  }

    public boolean dead() {
        return this.getSavings() < 0;
    }

    // simulation actions

    public void createOffers() {

         this.moveProfitToSavings();


      if (dead()) {
          return;
      }

        double basePrice = 1.1 + 3 * Math.random();

        market.clearOffers(this, Offer.Type.Sell);


        double total = 0;
        double  money = getSavings();

        while (total < 100 && money > 0) {
            // pick sizes of 5, 10, 15, 20
            double size = 5 + 15 * Math.random();

            size = Math.min(size, getSavings() / basePrice);

            long packSize = Math.round(size);
            packSize = 5 * (packSize / 5);

            if (packSize > 0) {

                double price = basePrice * packSize;

                total += packSize;

                Offer offer = new Offer(packSize, price, Offer.Type.Sell, (TransActionAgent) this, 1);

                // this is a transaction with the earth i guess
                this.payMoney(packSize);

                market.addOffer(offer);
            } else {
                // we are  done
                break;
            }
        }
    }

    public void processDividends() {
        
      if (dead()) {
          return;
      }

            // hand out dividends
	  // send profit to owners
	  double profit = getProfit();
	  if (owners.size() > 0 && profit > 0)
	  {
		  double numOwners = 0;

		  for(TransActionAgent owner : owners)
		  {
			  if (!owner.dead())
			  {
				  numOwners += 1;
			  }
		  }

		  if ( numOwners > 0) {
			  double dividend = margin * profit/numOwners;

			  for(TransActionAgent owner : owners) {
				  if (!owner.dead()) {

                      // need to create contract for this
					  owner.receiveMoney(dividend);
					  payMoney(dividend);
				  }
			  }
		  }
	  }
    }

    public Location getLoc() {
       return loc;
    }
}
